package com.lambda.hybrid;

import android.graphics.Bitmap;
import android.net.Uri;
import android.text.TextUtils;
import android.util.Log;

import com.lambda.hybrid.utils.Const;
import com.tencent.smtt.export.external.interfaces.WebResourceResponse;
import com.tencent.smtt.sdk.WebView;
import com.tencent.smtt.sdk.WebViewClient;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.HashMap;

public class HybridClient extends WebViewClient {
    private static final String TAG = Const.TAG;
    private final Runnable finishProgress = new Runnable() {
        @Override
        public void run() {
            mHybridView.setProgress(0.0f);
            mHybridView.progressFinish = true;
        }
    };

    private final HybridView mHybridView;
    private HashMap<Integer, Callback> mCallbackHashMap = new HashMap<>();
    private HashMap<String, HybridHandler> mHandlerHashMap = new HashMap<>();

    private int mCallbackIdGen = 1;

    public HybridClient(HybridView hybridView) {
        mHybridView = hybridView;
    }

    @Override
    public void onPageStarted(WebView webView, String s, Bitmap bitmap) {
        super.onPageStarted(webView, s, bitmap);
        mHybridView.removeCallbacks(finishProgress);
        mHybridView.progressFinish = false;
        mHybridView.postDelayed(finishProgress, 6000);
    }

    @Override
    public void onPageFinished(WebView view, String url) {
        mHybridView.hybridConfig.onPageFinished();
    }

    /**
     * [scheme:][//host:port][path][?query][#fragment]
     *
     * @param url the URL of the resource to load
     * @return handle
     */
    @Override
    public boolean shouldOverrideUrlLoading(WebView webView, String url) {
        boolean handle = false;
        if (url.startsWith(Const.HYBRID_SCHEME)) {
            Log.d(TAG, "Command: " + url);

            Uri uri = Uri.parse(url);
            try {
                String host = uri.getHost();

                if (TextUtils.isEmpty(host)) throw new IllegalArgumentException("host is empty");

                switch (host) {
                    case Const.CALLBACK:
                        onCallback(uri);
                        break;

                    case Const.INVOKE:
                        onInvoke(uri);
                        break;

                    default:
                        throw new IllegalArgumentException("unknown host: " + host);
                }
            } catch (Exception e) {
                mHybridView.loadUrl(BridgeHelper.err(Log.getStackTraceString(e)));
            }
            handle = true;
        } else if (!url.startsWith("http")) {
            handle = true;
        }
        return handle;
    }

    private void onCallback(Uri uri) {
        int cbid = Integer.parseInt(uri.getQueryParameter(Const.CALLBACK_ID));
        Callback callback = mCallbackHashMap.remove(cbid);
        if (callback != null) {
            callback.invoke(uri.getQueryParameter(Const.CALLBACK_DATA));
        }
    }

    private void onInvoke(Uri uri) {
        String name = uri.getQueryParameter(Const.FUNC_NAME);
        if (!TextUtils.isEmpty(name)) {
            HybridHandler handler = mHandlerHashMap.get(name);
            if (handler != null) {
                String cbidString = uri.getQueryParameter(Const.CALLBACK_ID);
                int cbid = Integer.parseInt(cbidString);
                handler.handle(uri.getQueryParameter(Const.FUNC_DATA), new JSCallback(mHybridView, cbid));
            }
        }
    }

    @Override
    public WebResourceResponse shouldInterceptRequest(WebView webView, String url) {
        if (TextUtils.isEmpty(url)) return null;

        WebResourceResponse response;
        if (url.endsWith("favicon.ico")) {
            try {
                Bitmap bitmap = Bitmap.createBitmap(16, 16, Bitmap.Config.RGB_565);
                ByteArrayOutputStream baos = new ByteArrayOutputStream(bitmap.getByteCount());
                bitmap.compress(Bitmap.CompressFormat.WEBP, 100, baos);
                response = new WebResourceResponse("image/webp", null, new ByteArrayInputStream(baos.toByteArray()));
            } catch (Exception e) {
                response = null;
            }
        } else {
            response = null;
        }

        return response;
    }

    public void register(String name, HybridHandler handler) {
        mHandlerHashMap.put(name, handler);
    }

    public void invoke(String name, String data, Callback callback) {
        int cbid = 0;
        if (callback != null) {
            cbid = mCallbackIdGen++;
            if (cbid == Integer.MAX_VALUE) {
                mCallbackIdGen = 1;
            }
            mCallbackHashMap.put(cbid, callback);
        }
        mHybridView.loadUrl(BridgeHelper.invoke(name, data, cbid));
    }

    private final static class JSCallback implements Callback {
        private final HybridView bridge;
        private final int cbid;

        private JSCallback(HybridView bridge, int cbid) {
            this.bridge = bridge;
            this.cbid = cbid;
        }

        @Override
        public void invoke(String data) {
            if (bridge != null && !TextUtils.isEmpty(data)) {
                bridge.loadUrl(BridgeHelper.callback(cbid, data));
            }
        }
    }
}
